#include <string.h>
#include <memory>
#include <thread>
#include <functional>
#include <stdio.h>
#include <iostream>
#include <unistd.h>

/*
 * 线程独立栈
 */

/*
 * 线程 之间存在 独立栈，可以保证彼此之前执行任务时不会相互干扰，可以通过代码证明
 * 
 * 多个线程使用同一个入口函数，并打印其中临时变量的地址
 */

using namespace std;

string toHex(pthread_t t)
{
    char id[64];
    snprintf(id, sizeof(id), "0x%x", t);
    return id;
}

void *threadRun(void *arg)
{
    int tmp = 0;
    cout << "thread " << toHex(pthread_self()) << " &tmp: " << &tmp << endl;

    return (void*)0;
}

int main()
{
    pthread_t t[5];
    for(int i = 0; i < 5; i++)
    {
        pthread_create(t + i, nullptr, threadRun, nullptr);
        sleep(1);
    }

    for(int i = 0; i < 5; i++)
        pthread_join(t[i], nullptr);
    return 0;
}

#if 0
/* 可以看到五个线程打印 “同一个” 临时变量的地址并不相同，足以证明 线程独立栈 的存在 */
thread 0x454df700 &tmp: 0x7fc8454deeac
thread 0x44cde700 &tmp: 0x7fc844cddeac
thread 0x3ffff700 &tmp: 0x7fc83fffeeac
thread 0x3f7fe700 &tmp: 0x7fc83f7fdeac
thread 0x3effd700 &tmp: 0x7fc83effceac

/* 存在这么多 栈结构，CPU 在运行时是如何区分的呢？ */

答案是通过 栈顶指针 ebp 和 栈底指针 esp 进行切换，ebp 和 esp 是 CPU 中两个非常重要的 寄存器，
即便是程序启动，也需要借助这两个 寄存器 为 main 函数开辟对应的 栈区，
除了移动 esp 扩大栈区外，还可以同时移动 ebp 和 esp 更改当前所处栈区。

所以，多线程中 独立栈 可以通过 ebp 和 esp 轻松切换并使用

     如果想要在栈区中开辟整型空间，可以使用 ebp - 4 定位对应的空间区域并使用，其他类型也是如此，原理都是 基地址 + 偏移量
     

注意：

    所有线程都要有自己独立的栈结构（独立栈），主线程中用的是进程系统栈，次线程用的是库中提供的栈
    多个线程调用同一个入口函数（回调方法），其中的局部变量地址一定不一样，因为存储在线程独立栈中

#endif
